package com.meis.widget.evaporate;

import com.meis.widget.utils.PixelUtil;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.text.SimpleTextLayout;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.app.Context;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by wenshi on 2018/11/22.
 * Description
 */
public class EvaporateTextView extends Text implements Component.DrawTask {
    protected int mHeight;
    protected int mWidth;
    protected String mText;
    protected String mOldText;
    protected Paint mPaint;
    protected Paint mOldPaint;
    // 每个字符的宽度集合
    protected List<Float> gapList = new ArrayList<>();
    protected List<Float> oldGapList = new ArrayList<>();
    protected float progress; //  0 ~ 1
    protected float mTextSize;
    protected float oldStartX = 0;
    private float charTime = 300;
    private int mostCount = 20;
    private int mTextHeight;
    private List<CharacterDiffResult> differentList = new ArrayList<>();
    private long duration;
    private AnimatorValue animator;

    public EvaporateTextView(Context context) {
        this(context, null);
    }

    public EvaporateTextView(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    public EvaporateTextView(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        PixelUtil.initContext(getContext());
        mOldText = "";
        mText = getText();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setColor(Color.WHITE);
        mOldPaint = new Paint(mPaint);
        mOldPaint.setAntiAlias(true);
        mOldPaint.setStyle(Paint.Style.FILL_STYLE);
        mOldPaint.setColor(Color.WHITE);

        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {
                mTextSize = getTextSize();
                mWidth = getWidth();
                mHeight = getHeight();
                oldStartX = 0;
                getOldStartX();
            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {
            }
        });
        setMaxTextLines(1);
        setTruncationMode(TruncationMode.ELLIPSIS_AT_END);
        prepareAnimate();
        // 初始化animator
        animator = new AnimatorValue();
        animator.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
        animator.setValueUpdateListener((animatorValue, v) -> {
            progress = v;
            invalidate();
        });
        int n = mText.length();
        n = n <= 0 ? 1 : n;
        duration = (long) (charTime + charTime / mostCount * (n - 1));
        addDrawTask(this);
    }

    @Override
    public void addDrawTask(DrawTask task) {
        super.addDrawTask(task);
        task.onDraw(this, mCanvasForTaskOverContent);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        // super.onDraw(canvas);  注释掉 重新绘制文本
        Rect rect = mPaint.getTextBounds(mText);
        SimpleTextLayout layout = new SimpleTextLayout(mText, mPaint, getComponentPosition(), rect.getWidth());
        float startX = (PixelUtil.screenWidth() - rect.getWidth()) >> 1;
        startX = Math.max(startX, 0);
        float startY = layout.getBaseline(0) + 50;
        float offset = startX;
        float oldOffset = oldStartX;
        int maxLength = Math.max(mText.length(), mOldText.length());
        for (int i = 0; i < maxLength; i++) {
            // draw old text
            if (i < mOldText.length()) {
                float pp = progress;
                mOldPaint.setTextSize((int) mTextSize);
                int move = CharacterUtils.needMove(i, differentList);
                if (move != -1) {
                    // 需要移动的字符 左右平移运动 视觉欺骗并没有上下的运动
                    mOldPaint.setAlpha(1);
                    // * 2f 平移速度
                    float p = pp * 2f;
                    p = p > 1 ? 1 : p;
                    float distX = CharacterUtils.getOffset(i, move, p, startX, oldStartX, gapList, oldGapList);
                    String txt = mOldText.charAt(i) + "";
                    canvas.drawText(mOldPaint, txt, distX, startY);
                } else {
                    mOldPaint.setAlpha(1 - pp);
                    float y = startY - pp * mTextHeight;
                    float width = mOldPaint.measureText(mOldText.charAt(i) + "");
                    // (oldGapList.get(i) - width) / 2 值为0   oldOffset + (oldGapList.get(i) - width) / 2
                    String txt = mOldText.charAt(i) + "";
                    canvas.drawText(mOldPaint, txt, oldOffset, y);
                }
                oldOffset += oldGapList.get(i);
            }
            if (i < mText.length()) {
                if (!CharacterUtils.stayHere(i, differentList)) {
                    // 渐显效果 延迟
                    int alpha = (int) (255f / charTime * (progress * duration - charTime * i / mostCount));
                    alpha = Math.min(alpha, 255);
                    alpha = Math.max(alpha, 0);
                    float alphaF = (float) ((double) alpha / (double) 255);
                    mPaint.setAlpha(alphaF);
                    mPaint.setTextSize((int) mTextSize);
                    float pp = progress;
                    float y = mTextHeight + startY - pp * mTextHeight;
                    float width = mPaint.measureText(mText.charAt(i) + "");
                    String txt = mText.charAt(i) + "";
                    canvas.drawText(mPaint, txt, offset + (gapList.get(i) - width) / 2, y);
                }
                offset += gapList.get(i);
            }
        }
    }

    public void setProgress(float progress) {
        this.progress = progress;
        invalidate();
    }

    public void animateText(String text) {
        mOldText = mText;
        mText = text;
        prepareAnimate();
        animatePrepare(text);
        animateStart();
    }

    private void animateStart() {
        int n = mText.length();
        n = n <= 0 ? 1 : n;
        duration = (long) (charTime + charTime / mostCount * (n - 1));
        animator.cancel();
        animator.setDuration(duration);
        animator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                getOldStartX();
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        animator.start();
    }

    private void getOldStartX() {
            Rect bounds = mPaint.getTextBounds(mText);
            int oldWidth = bounds.getWidth();
            oldStartX = (PixelUtil.screenWidth() - oldWidth) >> 1;
    }

    private void animatePrepare(String text) {
        differentList.clear();
        differentList.addAll(CharacterUtils.diff(mOldText, mText));
        Rect bounds = mPaint.getTextBounds(mText);
        mTextHeight = bounds.getHeight();
    }

    private void prepareAnimate() {
        // 初始化相关数据
        mTextSize = getTextSize();
        mPaint.setTextSize((int) mTextSize);
        gapList.clear();
        for (int i = 0; i < mText.length(); i++) {
            gapList.add(mPaint.measureText(String.valueOf(mText.charAt(i))));
        }
        mOldPaint.setTextSize((int) mTextSize);
        oldGapList.clear();
        for (int i = 0; i < mOldText.length(); i++) {
            oldGapList.add(mOldPaint.measureText(String.valueOf(mOldText.charAt(i))));
        }
    }
}
